#include <iostream>
#include <typeinfo>

#include "CSMsgDef.h"
#include "PBMsgHead.pb.h"
#include "MsgComm.pb.h"
#include "MsgTask.pb.h"
#include "MsgLogin.pb.h"
#include "commmsg.h"

using namespace std;

#define SVR_VERSION 1000

/*
class MsgReqGetTaskList;
class MsgReqAcceptTask;
class MsgReqCommitTask;
class MsgReqRemoveTask;
class MsgAnsGetTaskList;
class MsgTaskTarget;
*/

template<typename T>
class CTask
{
public:
	/* enp head info to pb */
	int DoReqHeadBody(PBMsgHead& Msghead, int argv[], char * szArg="");

	int Encode(PBMsgHead& Msghead, char* buff, int& iDataLength);

	int Decode(PBMsgHead& Msghead, char* buff, int& iDataLength);

	int OutputMsg(PBMsgHead& Msghead);

	T * GetPtr()
	{
		return (T*)&m_obj;
	}

private:
	int PromptWarn()
	{
		cout << "Error class type." << endl;
		return -1;
	}

private:
	T  m_obj;
};

template<typename T>
int CTask<T>::DoReqHeadBody(PBMsgHead& Msghead, int argv[], char * szArg)
{

	/* set msg head common part*/
	Msghead.set_version(SVR_VERSION);
	Msghead.set_time((int)time(NULL));
	Msghead.set_msgact(10);
	Msghead.set_msgtype(CSMsgDef::EMT_REQUEST);
	Msghead.set_msgret(0);

	if( typeid(MsgReqGetTaskList).name()==typeid(m_obj).name() )
	{
		Msghead.set_msgid(ID_MAIN_GET_TASK_LIST);

		MsgReqGetTaskList * stReq = dynamic_cast<MsgReqGetTaskList*>(&m_obj);

		stReq->set_gid((unsigned int)argv[0]);
	}
	else if( typeid(MsgReqAcceptTask).name()==typeid(m_obj).name() )
	{
		Msghead.set_msgid(ID_MAIN_ACCEPT_TASK);

		MsgReqAcceptTask * stReq = dynamic_cast<MsgReqAcceptTask*>(&m_obj);

		stReq->set_gid((unsigned int)argv[0]);
		stReq->set_task_id(argv[1]);
		stReq->set_npc_id(argv[2]);
	}
	else if( typeid(MsgReqCommitTask).name()==typeid(m_obj).name() )
	{
		Msghead.set_msgid(ID_MAIN_COMMIT_TASK);

		MsgReqCommitTask * stReq = dynamic_cast<MsgReqCommitTask*>(&m_obj);

		stReq->set_gid((unsigned int)argv[0]);
		stReq->set_task_id(argv[1]);
		stReq->set_npc_id(argv[2]);
	}
	else if( typeid(MsgReqRemoveTask).name()==typeid(m_obj).name() )
	{
		//Msghead.set_msgid(ID_MAIN_DEL_TASK);
		//nothing do
	}
	else if( typeid(MsgReqLogin).name()==typeid(m_obj).name() )
	{
		Msghead.set_msgid(ID_MAIN_LOGIN);

		MsgReqLogin* stReq = dynamic_cast<MsgReqLogin*>(&m_obj);

		stReq->set_user_token( szArg );
	}
	else
	{
		return this->PromptWarn();
	}
	return 0;
}

template<typename T>
int CTask<T>::Encode(PBMsgHead& Msghead, char* buff, int& iDataLength)
{
	T & stReq = m_obj;

	int iMsgHeadLen = Msghead.ByteSize();
	*(int*)(buff + sizeof(int)) = (int)htonl((int)iMsgHeadLen);
	Msghead.SerializeToArray((void*)(buff + sizeof(int) + sizeof(int)), Msghead.ByteSize());

	int iMsgBodyLen = stReq.ByteSize();
	*(int*)(buff + sizeof(int) + sizeof(int) + iMsgHeadLen) = (int)htonl((int)iMsgBodyLen);
	stReq.SerializeToArray((void*)(buff + sizeof(int) + sizeof(int) + iMsgHeadLen + sizeof(int)), stReq.ByteSize());

	*(char*)(buff + sizeof(int)*3 + iMsgHeadLen + iMsgBodyLen) = '\t';
	iDataLength = sizeof(int)*3 + iMsgHeadLen + iMsgBodyLen + sizeof(char);

	*(int*)(buff) = (int)htonl((int)iDataLength);

        return 0;
}

template<typename T>
int CTask<T>::Decode(PBMsgHead& Msghead, char* buff, int& iDataLength)
{
	T & stAns = m_obj;

	int iMsgTotalLen = ntohl(*(int*)buff);
	int iMsgHeadLen = ntohl(*(int*)(buff+sizeof(int)));
	int iMsgBodyLen = ntohl(*(int*)(buff+sizeof(int)+sizeof(int)+iMsgHeadLen));
	if (iMsgTotalLen <= 0)
	{
		printf("msglen error(%d)!\n",iMsgTotalLen);
		return -1;
	}
	if (buff[iMsgTotalLen - 1] != '\t')
	{
		printf("flag error(%d)!\n",buff[iMsgTotalLen - 1]);
		return -1;
	}

	Msghead.ParseFromArray((void*)(buff+sizeof(int)+sizeof(int)), iMsgHeadLen);
	if( Msghead.msgret()!=0 )
	{
		printf( "Parse form Msghead return value:%d.\n", Msghead.msgret() );
		return -1;
	}

	if (iMsgTotalLen != iMsgHeadLen + iMsgBodyLen + (int)sizeof(int)*3 + (int)sizeof(char))
	{
		printf("total length error!\n");
		return -1;
	}

	printf( "*length head:%d, body:%d, total:%d.\n", iMsgHeadLen, iMsgBodyLen, iMsgTotalLen );
	

	stAns.ParseFromArray((void*)(buff+sizeof(int)+sizeof(int)+iMsgHeadLen+sizeof(int)), iMsgBodyLen);

        return 0;
}

template<typename T>
int CTask<T>::OutputMsg(PBMsgHead& Msghead)
{
	printf("*MsgHead ver(%d) time(%d) act(%d) cmd(%d) msgret(%d)\n", Msghead.version(),Msghead.time(),Msghead.msgact(), Msghead.msgid(),Msghead.msgret());

	if( typeid(m_obj).name() == typeid(MsgAnsGetTaskList).name() )
	{
		MsgAnsGetTaskList * stAns = dynamic_cast<MsgAnsGetTaskList*>(&m_obj);
		cout << "has activate tasks:" << endl;
		for( int i = 0; i<stAns->task_can_get_size(); ++i )
		{
			cout << stAns->task_can_get(i) << "\t";
		}
		cout << "\ndetail:" << endl;
		//printf("Ans ret=%d sub_type=%d\n",stAns.ret(), stAns.sub_type());
		for(int i = 0; i < stAns->tasks_size(); ++i)
		{
			if( i==0 )
			{
				printf("index\t taskid\t task_status\t is_completed\t distination_type\t complete_cond\t cur_status\t data\n");
			}
			printf( "%d:\t %d\t %d\t\n", i, stAns->tasks(i).task_id(), stAns->tasks(i).task_stat() );
			for( int j=0; j<stAns->tasks(i).task_targets_size(); ++j )
			{
				MsgTaskTarget mTaskTarget = stAns->tasks(i).task_targets(j);
				printf( "\t \t \t %d\t %d\t %d\t %d\t %d\n", mTaskTarget.is_reach_cond(), mTaskTarget.cond_type(), mTaskTarget.finish_stat(), mTaskTarget.now_stat(), mTaskTarget.data1());
			}
		}
	}
	else if( typeid(m_obj).name() == typeid(MsgAnsLogin).name() )
	{
		MsgAnsLogin* stAns = dynamic_cast<MsgAnsLogin*>(&m_obj);

		//printf( "ret:%d, user gid:%d\n", /*stAns->ret(),*/ stAns->gid() );
		printf( "ret user gid:%d\n", /*stAns->ret(),*/ stAns->gid() );
	}
	else
	{
		return this->PromptWarn();
	}

	return 0;
}

